#include <bits/stdc++.h>

#define pb push_back
#define eb emplace_back
#define fi first
#define se second
#define in read<int>()
#define lin read<ll>()
#define rep(i, x, y) for(int i = (x); i <= (y); i++)
#define per(i, x, y) for(int i = (x); i >= (y); i--)

using namespace std;

using ll = long long;
using db = double;
using pii = pair < int, int >;
using vec = vector < int >;
using veg = vector < pii >;

template < typename T > T read() {
	T x = 0; bool f = 0; char ch = getchar();
	while(!isdigit(ch)) f |= ch == '-', ch = getchar();
	while(isdigit(ch)) x = x * 10 + (ch ^ 48), ch = getchar();
	return f ? -x : x;
}

template < typename T > void chkmax(T &x, const T &y) { x = x > y ? x : y; }
template < typename T > void chkmin(T &x, const T &y) { x = x < y ? x : y; }

const int TK = 110;
const int N = 1e4 + 10;

int l[TK][N], n, K, q, d, ans, tot[TK], x;
tuple < int, int, int > m[TK][N << 2];

int getrkm(int t, int pos) {
	if(get<0>(m[t][pos - 1]) >= x) return pos - 1;
	else if(get<0>(m[t][pos]) >= x) return pos;
	else return pos + 1;
}

int getrkl(int t, int pos) {
	//	cerr << "L : " << t << " " << pos << " " << x << " " << l[t][pos] << " " << l[t][pos + 1] << endl;
	if(l[t][pos] >= x) return l[t][pos];
	else return l[t][pos + 1];
}

int main() {
#ifndef ONLINE_JUDGE
	freopen("1.in", "r", stdin);
#endif
	n = in, K = in, q = in, d = in;
	rep(i, 1, K) { rep(j, 1, n) l[i][j] = in; sort(l[i] + 1, l[i] + n + 1); }
	rep(i, 1, n) m[K][i] = make_tuple(l[K][i], i, 0);
	m[K][n + 1] = make_tuple((int)2e9, n + 1, 0); tot[K] = n + 1;
	per(t, K - 1, 1) {
		rep(i, 1, n) m[t][i] = make_tuple(l[t][i], i, 0);
		tot[t] = n; rep(i, 2, tot[t + 1]) m[t][++tot[t]] = make_tuple(get<0>(m[t + 1][i]), 0, i), i++;
		inplace_merge(m[t] + 1, m[t] + n + 1, m[t] + tot[t] + 1);
		int cnt0 = 0, cnt1 = 0;
		rep(i, 1, tot[t]) {
			auto &v = m[t][i];
			if(get<1>(v) == 0) get<1>(v) = cnt0, cnt1 = get<2>(v);
			else get<2>(v) = (cnt1 < tot[t + 1] && get<0>(v) >= get<0>(m[t + 1][cnt1 + 1]) ? cnt1 + 1 : cnt1), cnt0 = get<1>(v);
		} m[t][++tot[t]] = make_tuple((int)2e9, n + 1, tot[t + 1] - 1);
		  // 		cerr << t << " -- " << endl;
		  // rep(i, 1, tot[t]) cerr << get<0>(m[t][i]) << " " << get<1>(m[t][i]) << " " << get<2>(m[t][i]) << endl;
		//cerr << endl;
	}
	rep(_, 1, q) {
		x = in ^ ans; ans = 0;
		int pos = lower_bound(m[1] + 1, m[1] + tot[1] + 1, make_tuple(x, 0, 0)) - m[1];
		ans = getrkl(1, get<1>(m[1][pos])); 
		//		cerr << 1 << " " << pos << " " << get<1>(m[1][pos]) << " " << x << endl;
		pos = getrkm(2, get<2>(m[1][pos]));
		rep(t, 2, K) {
			//	cerr << t << " " << pos << " " << get<1>(m[t][pos]) << " " << x << endl;
			ans ^= getrkl(t, get<1>(m[t][pos]));
			if(t < K) pos = getrkm(t + 1, get<2>(m[t][pos]));
		} if(_ % d == 0) printf("%d\n", ans);
	}
	return 0;
}
